/**
 * 性能优化工具
 * 提供防抖、节流、懒加载等功能
 */

/**
 * 防抖函数
 * @param func 要防抖的函数
 * @param delay 延迟时间（毫秒）
 * @returns 防抖后的函数
 */
export function debounce<T extends (...args: any[]) => any>(
  func: T,
  delay: number,
): (...args: Parameters<T>) => void {
  let timeoutId: ReturnType<typeof setTimeout>

  return (...args: Parameters<T>) => {
    clearTimeout(timeoutId)
    timeoutId = setTimeout(() => func(...args), delay)
  }
}

/**
 * 节流函数
 * @param func 要节流的函数
 * @param delay 节流间隔（毫秒）
 * @returns 节流后的函数
 */
export function throttle<T extends (...args: any[]) => any>(
  func: T,
  delay: number,
): (...args: Parameters<T>) => void {
  let lastCallTime = 0

  return (...args: Parameters<T>) => {
    const now = Date.now()
    if (now - lastCallTime >= delay) {
      lastCallTime = now
      func(...args)
    }
  }
}

/**
 * 一次性函数
 * @param func 只执行一次的函数
 * @returns 包装后的函数
 */
export function once<T extends (...args: any[]) => any>(func: T): T {
  let called = false
  let result: ReturnType<T>

  return ((...args: Parameters<T>) => {
    if (!called) {
      called = true
      result = func(...args)
    }
    return result
  }) as T
}

/**
 * 带缓存的函数
 * @param func 要缓存的函数
 * @param keyGenerator 缓存键生成器
 * @returns 带缓存的函数
 */
export function memoize<T extends (...args: any[]) => any>(
  func: T,
  keyGenerator?: (...args: Parameters<T>) => string,
): T {
  const cache = new Map<string, ReturnType<T>>()

  return ((...args: Parameters<T>) => {
    const key = keyGenerator ? keyGenerator(...args) : JSON.stringify(args)

    if (cache.has(key)) {
      return cache.get(key)!
    }

    const result = func(...args)
    cache.set(key, result)
    return result
  }) as T
}

/**
 * 懒加载管理器
 */
export class LazyLoader {
  private observers = new Map<Element, IntersectionObserver>()
  private callbacks = new Map<Element, () => void>()
  private defaultOptions: IntersectionObserverInit

  constructor(defaultOptions: IntersectionObserverInit = {}) {
    this.defaultOptions = {
      rootMargin: '50px',
      threshold: 0.1,
      ...defaultOptions,
    }
  }

  /**
   * 观察元素
   */
  observe(element: Element, callback: () => void, options?: IntersectionObserverInit) {
    if (!element)
      return

    const observerOptions = { ...this.defaultOptions, ...options }
    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          callback()
          this.unobserve(element)
        }
      })
    }, observerOptions)

    observer.observe(element)
    this.observers.set(element, observer)
    this.callbacks.set(element, callback)
  }

  /**
   * 停止观察元素
   */
  unobserve(element: Element) {
    const observer = this.observers.get(element)
    if (observer) {
      observer.unobserve(element)
      observer.disconnect()
      this.observers.delete(element)
      this.callbacks.delete(element)
    }
  }

  /**
   * 清除所有观察
   */
  disconnect() {
    this.observers.forEach(observer => observer.disconnect())
    this.observers.clear()
    this.callbacks.clear()
  }
}

/**
 * 图片懒加载
 */
export function lazyLoadImage(
  imgElement: HTMLImageElement,
  src: string,
  placeholder?: string,
): void {
  // 设置占位图
  if (placeholder) {
    imgElement.src = placeholder
  }

  // 创建懒加载管理器
  const lazyLoader = new LazyLoader()

  lazyLoader.observe(imgElement, () => {
    imgElement.src = src
    imgElement.onload = () => {
      imgElement.classList.add('loaded')
    }
    imgElement.onerror = () => {
      imgElement.classList.add('error')
      if (placeholder) {
        imgElement.src = placeholder
      }
    }
  })
}

/**
 * 虚拟滚动计算
 */
export interface VirtualScrollOptions {
  containerHeight: number
  itemHeight: number
  data: any[]
  overscan?: number // 预渲染的项目数量
}

export class VirtualScroll {
  private containerHeight: number
  private itemHeight: number
  private data: any[]
  private overscan: number

  constructor(options: VirtualScrollOptions) {
    this.containerHeight = options.containerHeight
    this.itemHeight = options.itemHeight
    this.data = options.data
    this.overscan = options.overscan || 5
  }

  /**
   * 获取可见区域的数据
   */
  getVisibleData(scrollTop: number) {
    const startIndex = Math.floor(scrollTop / this.itemHeight)
    const endIndex = Math.min(
      startIndex + Math.ceil(this.containerHeight / this.itemHeight) + this.overscan,
      this.data.length,
    )

    const visibleStartIndex = Math.max(0, startIndex - this.overscan)
    const visibleEndIndex = endIndex

    return {
      data: this.data.slice(visibleStartIndex, visibleEndIndex),
      startIndex: visibleStartIndex,
      endIndex: visibleEndIndex,
      offsetY: visibleStartIndex * this.itemHeight,
      totalHeight: this.data.length * this.itemHeight,
    }
  }

  /**
   * 滚动到指定项目
   */
  scrollToItem(index: number, container: HTMLElement) {
    const scrollTop = index * this.itemHeight
    container.scrollTop = scrollTop
  }

  /**
   * 更新数据
   */
  updateData(data: any[]) {
    this.data = data
  }
}

/**
 * 性能监控器
 */
export class PerformanceMonitor {
  private metrics = new Map<string, number>()

  /**
   * 开始计时
   */
  start(label: string) {
    this.metrics.set(label, performance.now())
  }

  /**
   * 结束计时并返回耗时
   */
  end(label: string): number {
    const startTime = this.metrics.get(label)
    if (!startTime) {
      console.warn(`性能监控：未找到标签 "${label}" 的开始时间`)
      return 0
    }

    const duration = performance.now() - startTime
    console.log(`性能监控 - ${label}: ${duration.toFixed(2)}ms`)
    this.metrics.delete(label)
    return duration
  }

  /**
   * 测量函数执行时间
   */
  measure<T>(label: string, fn: () => T): T {
    this.start(label)
    const result = fn()
    this.end(label)
    return result
  }

  /**
   * 异步测量函数执行时间
   */
  async measureAsync<T>(label: string, fn: () => Promise<T>): Promise<T> {
    this.start(label)
    const result = await fn()
    this.end(label)
    return result
  }
}

/**
 * 创建全局性能监控实例
 */
export const performanceMonitor = new PerformanceMonitor()

/**
 * 资源预加载
 */
export function preloadResources(resources: string[]): Promise<void[]> {
  const promises = resources.map((resource) => {
    if (resource.endsWith('.js') || resource.endsWith('.css')) {
      return preloadLink(resource)
    }
    else if (resource.match(/\.(jpg|jpeg|png|gif|webp|svg)$/i)) {
      return preloadImage(resource)
    }
    return Promise.resolve()
  })

  return Promise.all(promises)
}

function preloadLink(href: string): Promise<void> {
  return new Promise((resolve, reject) => {
    const link = document.createElement('link')
    link.rel = 'preload'
    link.href = href
    link.as = href.endsWith('.js') ? 'script' : 'style'
    link.onload = () => resolve()
    link.onerror = reject
    document.head.appendChild(link)
  })
}

function preloadImage(src: string): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    const img = new Image()
    img.onload = () => resolve(img)
    img.onerror = reject
    img.src = src
  })
}

/**
 * 批量DOM操作优化
 */
export function batchDOMUpdates(updates: (() => void)[]): void {
  // 使用 requestAnimationFrame 优化DOM操作
  requestAnimationFrame(() => {
    updates.forEach(update => update())
  })
}

/**
 * 防止内存泄漏的清理工具
 */
export class MemoryLeakPrevention {
  private timers: ReturnType<typeof setTimeout>[] = []
  private observers: IntersectionObserver[] = []
  private eventListeners: Array<{
    target: EventTarget
    type: string
    listener: EventListener
    options?: boolean | AddEventListenerOptions
  }> = []

  /**
   * 添加定时器
   */
  addTimer(timer: ReturnType<typeof setTimeout>) {
    this.timers.push(timer)
  }

  /**
   * 添加观察器
   */
  addObserver(observer: IntersectionObserver) {
    this.observers.push(observer)
  }

  /**
   * 添加事件监听器
   */
  addEventListener(
    target: EventTarget,
    type: string,
    listener: EventListener,
    options?: boolean | AddEventListenerOptions,
  ) {
    target.addEventListener(type, listener, options)
    this.eventListeners.push({ target, type, listener, options })
  }

  /**
   * 清理所有资源
   */
  cleanup() {
    // 清理定时器
    this.timers.forEach(timer => clearTimeout(timer))
    this.timers = []

    // 断开观察器
    this.observers.forEach(observer => observer.disconnect())
    this.observers = []

    // 移除事件监听器
    this.eventListeners.forEach(({ target, type, listener, options }) => {
      target.removeEventListener(type, listener, options)
    })
    this.eventListeners = []
  }
}
